package com.lab303.powerproject.service.impl;

import com.lab303.powerproject.entity.Device;
import com.lab303.powerproject.entity.EnergyType;
import com.lab303.powerproject.entity.GraphInfo;
import com.lab303.powerproject.entity.Relationship;
import com.lab303.powerproject.pojo.CustomDevice;
import com.lab303.powerproject.repository.DeviceRepository;
import com.lab303.powerproject.repository.EnergyTypeRepository;
import com.lab303.powerproject.repository.GraphInfoRepository;
import com.lab303.powerproject.repository.RelationshipRepository;
import com.lab303.powerproject.service.DeviceService;
import com.lab303.powerproject.service.GraphInfoService;
import com.lab303.powerproject.service.RelationshipService;
import org.dom4j.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class GraphInfoServiceImpl implements GraphInfoService {

    @Autowired
    private GraphInfoRepository graphInfoRepository;

    @Autowired
    private RelationshipRepository relationshipRepository;

    @Autowired
    private DeviceRepository deviceRepository;

    @Autowired
    private EnergyTypeRepository energyTypeRepository;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private RelationshipService relationshipService;


    @Override
    public List<GraphInfo> getAllGraphInfo() {
        return graphInfoRepository.findAll();
    }

    @Override
    public List<GraphInfo> findGraphInfosByRemark(String remark){return graphInfoRepository.findGraphInfosByRemark(remark);}

    @Override
    public GraphInfo addOneGraphInfo(GraphInfo graphInfo) {
        return graphInfoRepository.saveAndFlush(graphInfo);
    }

    @Override
    public GraphInfo findGraphInfoById(Integer id) {
        return graphInfoRepository.findById(id).orElse(null);
    }

    @Override
    public GraphInfo saveAndFlush(GraphInfo graphInfo) {
        return graphInfoRepository.save(graphInfo);
    }

    @Override
    public void deleteGraphInfoByGraphId(Integer graphId) {
        graphInfoRepository.deleteById(graphId);
    }

    @Override
    @Transactional
    public String updateGraphByXmlString(Integer graphId, String xmlString) {
        Map<String, List> map = readStringXml(xmlString, graphId);
        StringBuffer stringBuffer = new StringBuffer();
        if (map==null){
            stringBuffer.append("edgeError");
        }else {

            List<Device> deviceList = map.get("device");
            List relationshipList = map.get("relationship");

            List<CustomDevice> byGraphId = deviceService.getDevicesByGraphId(graphId);
            Map hash = new HashMap();
            for (Device d : deviceList) {
                hash.put(d.getDeviceId(), d);
            }

            for (CustomDevice d : byGraphId) {
                if (!hash.containsKey(d.getDeviceId())) {
                    Device device = new Device();   //排除图谱之外
                    deviceRepository.updateDeviceIsInGraph(0, d.getDeviceId());
                }
            }

            //删除原边关系
            relationshipRepository.deleteRelationshipsByGraphId(graphId);

            deviceService.updateDeviceCoordinatesAndIsInGraph(deviceList); //修改设备坐标并修改标志位
            relationshipRepository.saveAll(relationshipList);  //添加边
            stringBuffer.append("success");
        }
        return stringBuffer.toString();
    }

    @Override
    @Transactional
    public void deleteAllGraphInfoByGraphId(Integer graphId) {
        deviceService.deleteDeviceByGraphId(graphId);
        relationshipService.deleteRelationshipByGraphId(graphId);
        deleteGraphInfoByGraphId(graphId);
    }

    public Map<String, List> readStringXml(String xml, Integer graphId) {
        Map<String,List> map = new HashMap<>();
        Document doc = null;
        List<Device> list = new ArrayList<>();
        List<Relationship> list1 = new ArrayList<>();
        try {
            doc = DocumentHelper.parseText(xml); // 将字符串转为XML
            Element mxGraphModel = doc.getRootElement();
            Element root = mxGraphModel.element("root");
            List<Element> childElements = root.elements();
            for (Element child : childElements) {
                //未知属性名情况下
            /*List<Attribute> attributeList = child.attributes();
            for (Attribute attr : attributeList) {
                System.out.println(attr.getName() + ": " + attr.getValue());
            }*/
                Attribute vertex = child.attribute("vertex");
                Attribute edge = child.attribute("edge");
                //确定是设备
                if (vertex!=null&&!"".equals(vertex.getValue())){
                    Device device = new Device();
                    String id = child.attribute("id").getValue();
                    Element mxGeometry = child.element("mxGeometry");
                    if (mxGeometry.attribute("x")!=null) {
                        String x = mxGeometry.attribute("x").getValue();
                        device.setxCoordinates(Float.valueOf(x));
                    }else {
                        device.setxCoordinates(0);
                    }
                    device.setDeviceId(Integer.parseInt(id));
                    if (mxGeometry.attribute("y")!=null) {
                        String y = mxGeometry.attribute("y").getValue();
                        device.setyCoordinates(Float.valueOf(y));
                    }else {
                        device.setyCoordinates(0);
                    }
                    device.setIsInGraph(1);
                    list.add(device);
                    System.out.println("解析xml串：id : " + id+"  x : "+device.getxCoordinates()+"  y : "+device.getyCoordinates());
                }else if (edge!=null&&!"".equals(edge.getValue())){
                    Attribute source = child.attribute("source");
                    Attribute target = child.attribute("target");
                    if (source==null||target==null){
                        return null;
                    }else {
                        Integer from = Integer.valueOf(source.getValue());
                        Integer to = Integer.valueOf(target.getValue());
                        String value = child.attribute("value").getValue();
                        EnergyType energyTypeByTypeName = energyTypeRepository.findEnergyTypeByTypeName(value);
                        Relationship relationship = new Relationship();
                        relationship.setDeviceFrom(from);
                        relationship.setDeviceTo(to);
                        relationship.setTypeId(energyTypeByTypeName.getTypeId());
                        relationship.setGraphId(graphId);
                        list1.add(relationship);
                    }
                }
            }
        }catch(DocumentException e){
            e.printStackTrace();
        }
        map.put("device",list);
        map.put("relationship",list1);
        return map;



    }
}
